package core;

import java.io.IOException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import net.server.ChatHttpServer;
import ui.ChatWindow;
import ui.MainWindow;
import db.Mapper;

public class ChatNode
{
	public static void main(String[] args)
	{
		switch(args.length)
		{
		case 0:
			new ChatNode("peers.txt");
			break;
		case 1:
			new ChatNode(args[0]);
			break;
		default:
			System.out.println("Program requires only one input parameter");
			break;
		}
	}
	
	private MainWindow mainWindow;
	private Map<String, ChatWindow> chatWindows;
	private ChatHttpServer server;
	private Mapper userbase;
	private LoginTask login;
	private FindTask find;
	private RequestBroadcaster broadcaster;
	
	private String dbfile;
	private String name;
	private String ip;
	private String port;
	
	public ChatNode(String filename)
	{
		mainWindow = new MainWindow(this);
		chatWindows = new ConcurrentHashMap<String, ChatWindow>();
		dbfile = filename;
		
		try
		{
			mainWindow.setAddresses(ChatHttpServer.getViableAddresses());
		}
		catch(SocketException ex)
		{
			mainWindow.appendText("ERROR: Unable to require ip adresses. " + ex.getMessage());
		}
		catch(UnknownHostException ex)
		{
			mainWindow.appendText("ERROR: Unable to require ip adresses " + ex.getMessage());
		}
	}
	
	public ChatHttpServer getServer()
	{
		return this.server;
	}
	
	public String getName()
	{
		return this.name;
	}
	
	public String getIp()
	{
		return this.ip;
	}
	
	public String getPort()
	{
		return this.port;
	}
	
	public Mapper getUserBase()
	{
		return this.userbase;
	}
	
	public MainWindow getMainWindow()
	{
		return this.mainWindow;
	}
	
	public FindTask getFindTask()
	{
		return this.find;
	}
	
	public void endFindTask()
	{
		this.find = null;
	}
	
	public void setupFindTask(String name)
	{
		find = new FindTask(name, this);
	}
	
	public ChatWindow getChatWindow(String id)
	{
		ChatWindow chatWindow;
		if(!chatWindows.containsKey(id))
		{
			chatWindow = new ChatWindow(this, id);
			chatWindows.put(id, chatWindow);
		}
		else
		{
			chatWindow = chatWindows.get(id);
			chatWindow.setVisible(true);
		}
		return chatWindow;
	}
	
	public LoginTask getLoginTask()
	{
		return this.login;
	}
	
	public RequestBroadcaster getRequestBroadcaster()
	{
		return this.broadcaster;
	}
	
	public void removeWindow(String id)
	{
		chatWindows.remove(id);
	}
	
	public void setIp(String ip)
	{
		this.ip = ip;
	}
	
	public void setName(String name)
	{
		this.name = name;
	}
	
	public void startServer(String name, String port)
	{
		int port_int = -1;
		try
		{
			port_int = Integer.parseInt(port);
			if(port_int < 1024 || port_int > 49151)
			{
				throw new NumberFormatException();
			}
		}
		catch(NumberFormatException ex)
		{
			mainWindow.appendText("Unable to set port. Valid range: 1024-49151");
		}
		
		if(port_int != -1 && !name.equals(""))
		{
			try
			{
				server = new ChatHttpServer(this, mainWindow.getAddress() ,port_int);
				this.port = port;
				this.ip = mainWindow.getAddress();
				
				mainWindow.appendText("INFO: Server is listening on " + ip + ":" + port);
			}
			catch(IOException ex)
			{
				mainWindow.appendText("Unable to start server. Reason: " + ex.getMessage());
			}
			
			
			if(server != null)
			{
				userbase = new Mapper(dbfile);
				broadcaster = new RequestBroadcaster(this);
				
				String myAddress = getIp() + ":" + getPort();
				
				//broadcast request 
				broadcaster.broadcastFindName(name, myAddress, 3);
				
				mainWindow.appendUser("Loggin in 3");
				login = new LoginTask(name, this);
				
				login.execute();
				
			}
			else
			{
				//server == null
				mainWindow.appendText("Unable to start server.");
			}
			
		}
		else
		{
			mainWindow.appendText("Name is required! Server start interrupted.");
		}
		
		
	}
	
	public synchronized void stopServer()
	{
		
		if(server != null)
		{
			server.stop();
		}
		
		if(!(chatWindows.isEmpty()))
		{
			Iterator<Entry<String, ChatWindow>> iter = chatWindows.entrySet().iterator();
			while(iter.hasNext())
			{
				ChatWindow current = iter.next().getValue();
				current.setVisible(false);
				current.dispose();
			}
			chatWindows.clear();
		}
		
		//TODO: peaks salvestama kontaktid faili
		
		name = null;
		port = null;
		ip = null;
		server = null;
		userbase = null;
		broadcaster = null;
		
		chatWindows.clear();
		
		mainWindow.appendText("INFO: Server is offline.");
	}
	
	
}
